<template>
  <div class="adaptive-component voice-bg">
    <div class="manage-voice-bg" v-if="!isMobile">
      <div
        :class="
          !showText && !showRobot ? 'voice-center noShowRobot' : 'voice-center'
        "
      >
        <div class="voice-avatar-cont" v-if="!showText && !showRobot">
          <div class="voice-avatar"><img :src="robotAvatar" /></div>
          <div class="voice-icon">{{ robotName }}</div>
        </div>
        <div
          :class="
            showText ? 'voice-avatar-robot with-txt' : 'voice-avatar-robot'
          "
          v-if="showRobot"
        >
          <!-- <div id="local_video"></div> -->
          <Loading v-if="!showRobotVideo" />
          <div
            id="remote_video"
            class="remote-video"
            :class="
              avatar_name === 'zhiming'
                ? 'remote-video zhiming'
                : avatar_name === '客服小云'
                ? 'remote-video lke2'
                : avatar_name === '客服小腾'
                ? 'remote-video lke1'
                : 'remote-video yoyo'
            "
          ></div>
        </div>
        <div
          :class="showRobot ? 'voice-info-cont robot-txt' : 'voice-info-cont'"
          v-if="showText || showRobotTxt"
          ref="msgContainer"
        >
          <div
            v-for="(item, index) in subtitleMsg"
            :key="index"
            :class="item.userid === userId ? 'user-question' : 'user-answer'"
          >
            {{ item.text }}
          </div>
        </div>
      </div>
      <div class="voice-op-cont">
        <div v-if="!isRobotReplying" class="voice-loading-cont">
          <div v-if="!isThinking" class="loader-voice">
            <div class="voice-loading">
              <div class="load"></div>
              <div class="load"></div>
              <div class="load"></div>
              <div class="load"></div>
            </div>
          </div>
          <div v-if="isThinking" class="typing-indicator">
            <div
              :class="
                thinkAnimating
                  ? 'typing-circle circle-animation'
                  : 'typing-circle'
              "
            ></div>
            <div
              :class="
                thinkAnimating
                  ? 'typing-circle circle-animation'
                  : 'typing-circle'
              "
            ></div>
            <div
              :class="
                thinkAnimating
                  ? 'typing-circle circle-animation'
                  : 'typing-circle'
              "
            ></div>
          </div>
          <div v-if="stopCount < 20 && !isThinking" class="voice-loader-txt">
            {{ `数智人将在 ${stopCount}s 后离开` }}
          </div>
          <div v-if="stopCount === 20 && !isThinking" class="voice-loader-txt">
            {{ "我在聆听" }}
          </div>
          <div v-if="isThinking" class="voice-loader-txt">
            {{ "正在思考中" }}
          </div>
        </div>
        <div
          v-else
          class="voice-loading-cont icon-pointer"
          @click="sendInterruptSignal"
        >
          <div class="loader-voice">
            <v-icon
              remote
              name="basic_stop_fill"
              style="width: 32px; height: 32px"
            />
          </div>
          <div class="voice-loader-txt">{{ "说话或点击打断" }}</div>
        </div>
        <div class="voice-btn-cont">
          <div class="voice-btn-mic" @click="toggleMic">
            <div class="mic-ico">
              <v-icon
                remote
                :name="
                  isMicOpen
                    ? 'device_microphone_fill'
                    : 'device_microphone_disabled_fiil'
                "
                class="mic-icon"
              />
            </div>
            <div class="mic-txt">
              {{ isMicOpen ? "麦克风已开" : "麦克风已关" }}
            </div>
          </div>
          <div class="handup-btn-mic" @click="leave">
            <div class="mic-ico">
              <v-icon remote name="basic_call_fill" class="mic-icon" />
            </div>
            <div class="mic-txt">挂断</div>
          </div>
          <div class="script-btn-mic" @click="taggleShowText">
            <div class="mic-ico">
              <v-icon
                remote
                :name="showText ? 'text_fill' : 'text_disabled_fill'"
                class="mic-icon"
              />
            </div>
            <div class="mic-txt">{{ showText ? "字幕已开" : "字幕已关" }}</div>
          </div>
        </div>
      </div>
      <div class="info">以上内容由AI 生成，仅供参考</div>
    </div>
    <div class="mobile-voice-bg" v-if="isMobile">
      <div
        :class="
          !showText && !showRobot ? 'voice-center noShowRobot' : 'voice-center'
        "
      >
        <div class="voice-avatar-cont" v-if="!showText && !showRobot">
          <div class="voice-avatar"><img :src="robotAvatar" /></div>
          <div class="voice-icon">{{ robotName }}</div>
        </div>
        <div
          :class="
            showText ? 'voice-avatar-robot with-txt' : 'voice-avatar-robot'
          "
          v-if="showRobot"
        >
          <!-- <div id="local_video"></div> -->
          <Loading v-if="!showRobotVideo" />
          <div
            v-else
            id="remote_video"
            class="remote-video"
            :class="
              avatar_name === 'zhiming'
                ? 'remote-video zhiming'
                : avatar_name === '客服小云'
                ? 'remote-video lke2'
                : avatar_name === '客服小腾'
                ? 'remote-video lke1'
                : 'remote-video yoyo'
            "
          ></div>
        </div>
        <div
          :class="showRobot ? 'voice-info-cont robot-txt' : 'voice-info-cont'"
          v-if="showText || showRobotTxt"
          ref="msgContainer"
        >
          <div
            v-for="(item, index) in subtitleMsg"
            :key="index"
            :class="item.userid === userId ? 'user-question' : 'user-answer'"
          >
            {{ item.text }}
          </div>
        </div>
      </div>
      <div class="voice-op-cont">
        <div v-if="!isRobotReplying" class="voice-loading-cont">
          <div v-if="!isThinking" class="loader-voice">
            <div class="voice-loading">
              <div class="load"></div>
              <div class="load"></div>
              <div class="load"></div>
              <div class="load"></div>
            </div>
          </div>
          <div v-if="isThinking" class="typing-indicator">
            <div
              :class="
                thinkAnimating
                  ? 'typing-circle circle-animation'
                  : 'typing-circle'
              "
            ></div>
            <div
              :class="
                thinkAnimating
                  ? 'typing-circle circle-animation'
                  : 'typing-circle'
              "
            ></div>
            <div
              :class="
                thinkAnimating
                  ? 'typing-circle circle-animation'
                  : 'typing-circle'
              "
            ></div>
          </div>
          <div v-if="stopCount < 20 && !isThinking" class="voice-loader-txt">
            {{ `数智人将在 ${stopCount}s 后离开` }}
          </div>
          <div v-if="stopCount === 20 && !isThinking" class="voice-loader-txt">
            {{ "我在聆听" }}
          </div>
          <div v-if="isThinking" class="voice-loader-txt">
            {{ "正在思考中" }}
          </div>
        </div>
        <div
          v-else
          class="voice-loading-cont icon-pointer"
          @click="sendInterruptSignal"
        >
          <div class="loader-voice">
            <v-icon
              remote
              name="basic_stop_fill"
              style="width: 32px; height: 32px"
            />
          </div>
          <div class="voice-loader-txt">{{ "说话或点击打断" }}</div>
        </div>
        <div class="voice-btn-cont">
          <div class="voice-btn-mic" @click="toggleMic">
            <div class="mic-ico">
              <v-icon
                remote
                :name="
                  isMicOpen
                    ? 'device_microphone_fill'
                    : 'device_microphone_disabled_fiil'
                "
                class="mic-icon"
              />
            </div>
          </div>
          <div class="handup-btn-mic" @click="leave">
            <div class="mic-ico">
              <v-icon remote name="basic_call_fill" class="mic-icon" />
            </div>
          </div>
          <div class="script-btn-mic" @click="taggleShowText">
            <div class="mic-ico">
              <v-icon
                remote
                :name="showText ? 'text_fill' : 'text_disabled_fill'"
                class="mic-icon"
              />
            </div>
          </div>
        </div>
      </div>
      <div class="info">以上内容由AI 生成，仅供参考</div>
    </div>
  </div>
</template>

<script>
import "../utils/ClientData";
import Loading from "../components/workspace/loading.js";
import { getQueryVariable, getShareCode } from "@/utils";

/**
 * Creates a message payload with common attributes
 * @param {number} type - Message type from MESSAGE_TYPES
 * @param {Object} payloadData - The payload data
 * @returns {Object} The formatted message payload
 */
function createMessagePayload(type, payloadData, sender, receiver) {
  return {
    type: type,
    sender,
    receiver: [receiver],
    payload: {
      id: Date.now().toString(),
      timestamp: Date.now(),
      ...payloadData,
    },
  };
}
// Message types for TRTC custom messages
const MESSAGE_TYPES = Object.freeze({
  CONVERSATION: 10000,
  STATE_CHANGE: 10001,
  CUSTOM_TEXT: 20000,
  CUSTOM_INTERRUPT: 20001,
  ERROR_CALLBACK: 10030,
  METRICS_CALLBACK: 10020,
});
// TRTC configuration constants
const TRTC_CONFIG = {
  CMD_ID: 2, // Fixed cmdId as per requirement
  VOLUME_EVALUATION_INTERVAL: 50, // 50ms for smoother visualization
};
// 进入实时通话的逻辑
// 通过接口获取TRTC 密钥构建TRTC的ws链接
// 把链接里的text内容显示在里面
// 聆听状态，说话状态转换
// 挂断电话
// 麦克风状态绑定
const TRTC = window.TRTC;
const roomidList = [
  10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010,
];
export default {
  name: "ClientVoice",
  components: {
    Loading,
  },
  data() {
    return {
      trtcState: "",
      robotName: "",
      robotAvatar: "",
      dhAvatar: "",
      isMicOpen: false,
      showText: false,
      showRobot: false,
      showRobotVideo: false,
      userId: "",
      userSig: "",
      robotUserId: "",
      robotUserSig: "",
      avatarUserId: "",
      avatarUserSig: "",
      taskId: "",
      roomId: 18272,
      localSdkappId: "",
      trtcSdkAppid: "",
      websocketProxy: "",
      subtitleMsg: [],
      subtitleText: "",
      transcriptionText: "",
      asrLanguageSelect: "zh",
      trtcClient: null,
      temp_token: "",
      avatar_img: "",
      avatar_name: "",
      stopCount: 20,
      stopTimer: null,
      isThinking: false,
      thinkAnimating: false,
      startCountTimer: null,
      isRobotReplying: false,
    };
  },
  mounted() {
    this.trtcState === "" && this.join();
    console.log("this.join()");
  },
  created() {
    // 监听postmessage事件
    // window.addEventListener('message', this.listenMessageEvent);
    const cachedConfig = this.$clientData.getConfigInfo();
    console.log(
      "cachedConfigcachedConfigcachedConfigcachedConfigcachedConfig",
      cachedConfig
    );

    if (cachedConfig) {
      this.showRobot = cachedConfig.ai_call.enable_digital_human;
      this.robotName = cachedConfig.name;
      this.robotAvatar = cachedConfig.avatar;
      if (cachedConfig.ai_call && cachedConfig.ai_call.digital_human) {
        this.dhAvatar = cachedConfig.ai_call.digital_human.avatar;
        this.avatar_name = cachedConfig.ai_call.digital_human.name;
      }
    }
    // 监听配置信息，获取机器人名称
    this.$eventHub.$on("client_configChange", (res) => {
      console.log("client_configChange", res);
      this.showRobot = res.ai_call.enable_digital_human;
      this.robotName = res.name;
      this.robotAvatar = res.avatar;
      if (res.ai_call && res.ai_call.digital_human) {
        this.dhAvatar = res.ai_call.digital_human.avatar;
        this.avatar_name = cachedConfig.ai_call.digital_human.name;
      }
    });
    this.$eventHub.$on("ai_config_change", (res) => {
      console.log("ai_config_change", res.aiconfig);
      this.showRobot = res.aiconfig.enable_digital_human;
      // this.dhAvatar = res.ai_call.digital_human.avatar;
      // this.avatar_name = cachedConfig.ai_call.digital_human.name;
    });
  },
  // computed: {
  //     isRobotReplying () {
  //         const len = this.subtitleMsg.length;
  //         if (
  //             len > 0 &&
  //     this.subtitleMsg[len - 1].userid === `${this.userId}_robot` &&
  //     this.subtitleMsg[len - 1].end === false
  //         ) {
  //             return true;
  //         }
  //         return false;
  //     }
  // },
  beforeDestroy() {
    // this.stopTranscription();
    // window.removeEventListener('message', this.listenMessageEvent);
  },
  watch: {
    // 监听消息数组变化
    subtitleMsg: {
      handler() {
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      },
      deep: true,
    },
  },
  methods: {
    scrollToBottom() {
      const container = this.$refs.msgContainer;
      if (container) {
        // 滚动到底部
        container.scrollTop = container.scrollHeight;
      }
    },
    toggleMic() {
      if (this.isMicOpen) {
        this.stopMic();
      } else {
        this.startMic();
      }
    },
    async stopMic() {
      if (this.trtcClient) {
        await this.trtcClient.updateLocalAudio({ mute: true });
      }
      this.isMicOpen = false;
    },
    async startMic() {
      if (this.trtcClient) {
        await this.trtcClient.updateLocalAudio({ mute: false });
      }
      this.isMicOpen = true;
    },
    handleMessage(data) {
      if (data.type === 10030) {
        if (data.payload.metric === "llm_error" && data.payload.tag) {
          console.log(
            "trtc 错误：",
            data.payload.metric,
            data.payload.tag.code,
            data.payload.tag.message
          );
          this.$message.error(`trtc 错误：${data.payload.metric}`);
        }
      }
      if (
        ((this.showRobot && this.showRobotVideo) || !this.showRobot) &&
        data.type === 10001 &&
        data.sender === this.robotUserId &&
        (data.payload.state === 1 || data.payload.state === 4)
      ) {
        this.isRobotReplying = false; // 机器人 1 聆听中 4 被打断
        this.isThinking = false;
        this.thinkAnimating = false;
      }
      if (
        ((this.showRobot && this.showRobotVideo) || !this.showRobot) &&
        data.type === 10001 &&
        data.sender === this.robotUserId &&
        data.payload.state === 2
      ) {
        this.isRobotReplying = false; // 机器人说话 2 思考中 3 说话中
        this.isThinking = true;
        setTimeout(() => {
          this.thinkAnimating = true;
        }, 1000);
      }
      if (
        ((this.showRobot && this.showRobotVideo) || !this.showRobot) &&
        data.type === 10001 &&
        data.sender === this.robotUserId &&
        data.payload.state === 3
      ) {
        this.isRobotReplying = true; // 机器人说话 2 思考中 3 说话中
        this.isThinking = false;
      }
      if (data.type === 10000 && data.payload.end === false) {
        // 实时的字幕
        console.log(
          "data.type === 10000 && data.payload.end === false",
          data.sender,
          this.userId,
          data.payload.text,
          data.payload.translation_text
        );
        // 修改前一个值或者打断前一个值
        // 提取最后一条字幕消息和通用的新消息创建逻辑
        const lastIndex = this.subtitleMsg.length - 1;
        const lastMsg = lastIndex >= 0 ? this.subtitleMsg[lastIndex] : null;
        const newSubtitleMsg = {
          userid: data.sender,
          text: data.payload.text,
          end: false,
        };

        // 简化逻辑流程
        if (lastMsg && !lastMsg.end) {
          if (data.sender === lastMsg.userid) {
            // 同一用户继续说话，更新文本
            if (data.sender === this.userId) {
              this.$set(this.subtitleMsg[lastIndex], "text", data.payload.text);
            } else {
              if (roomidList.includes(this.roomId)) {
                this.$set(
                  this.subtitleMsg[lastIndex],
                  "text",
                  data.payload.text
                );
              } else {
                this.$set(
                  this.subtitleMsg[lastIndex],
                  "text",
                  `${this.subtitleMsg[lastIndex].text}${data.payload.text}`
                );
              }
            }
            // lastMsg.text = data.payload.text;
          } else {
            // 新用户开始说话，结束上一条并添加新消息
            // lastMsg.end = true;
            this.$set(this.subtitleMsg[lastIndex], "end", true);
            this.subtitleMsg.push(newSubtitleMsg);
          }
        } else {
          // 没有未结束的消息，直接添加新消息
          this.subtitleMsg.push(newSubtitleMsg);
        }
      } else if (data.type === 10000 && data.payload.end === true) {
        console.log(
          "data.type === 10000 && data.payload.end === true",
          data.sender,
          data.payload.text,
          data.payload.translation_text
        );
        // 一句话识别完成
        // 修改前一个值或者打断前一个值
        const lastIndex = this.subtitleMsg.length - 1;
        const lastMsg = this.subtitleMsg[lastIndex];
        const isLastMsgIncomplete = lastMsg && lastMsg.end === false;
        const isSameSender =
          isLastMsgIncomplete && data.sender === lastMsg.userid;

        if (isSameSender) {
          // 更新未完成的同一用户的消息
          if (data.sender === this.userId) {
            this.$set(this.subtitleMsg[lastIndex], "text", data.payload.text);
          } else {
            if (roomidList.includes(this.roomId)) {
              this.$set(this.subtitleMsg[lastIndex], "text", data.payload.text);
            } else {
              this.$set(
                this.subtitleMsg[lastIndex],
                "text",
                `${this.subtitleMsg[lastIndex].text}${data.payload.text}`
              );
            }
          }
          this.$set(this.subtitleMsg[lastIndex], "end", true);
        } else {
          // 添加新消息(无论上一条是否完成)
          this.subtitleMsg.push({
            userid: data.sender,
            text: data.payload.text,
            end: true,
          });
        }
      }
    },
    sendInterruptSignal() {
      if (!this.trtcClient) return false;

      const payload = createMessagePayload(
        MESSAGE_TYPES.CUSTOM_INTERRUPT,
        {},
        this.userId,
        `${this.userId}_robot`
      );

      const data = {
        cmdId: TRTC_CONFIG.CMD_ID,
        data: new TextEncoder().encode(JSON.stringify(payload)).buffer,
      };

      this.trtcClient.sendCustomMessage(data);
    },
    async startTranscription() {
      this.trtcState = "transcription";
    },
    async stopTranscription() {
      if (!this.taskId) {
        return;
      }
      this.trtcState = "join";
    },
    async leave() {
      this.$emit("stopVoice");
      const payload = JSON.stringify({
        from: "webim",
        type: "voice-call-change",
        value: false,
      });
      window.parent && window.parent.postMessage(payload, "*");
      await this.stopTranscription();
      if (this.trtcClient) {
        await this.trtcClient.exitRoom();
        // 退房成功后，若后续无需使用 trtc 实例，则可以调用 trtc.destroy 方法销毁实例，及时释放相关资源。销毁后的 trtc 实例无法继续使用，需要重新创建新的实例。
        this.trtcClient.destroy();

        this.trtcClient = null;
      }
      this.trtcState = "leave";
      this.userSig = "";
      this.$clientData.clearCache();
      this.$clientData.getHistory(false, "stopVoice");
    },
    resetStopTimer() {
      this.stopTimer && clearTimeout(this.stopTimer);
      this.startCountTimer && clearInterval(this.startCountTimer);
      this.stopCount = 20;
      this.stopTimer = setTimeout(() => {
        this.startCount();
      }, 3600 * 1000);
    },
    startCount() {
      this.startCountTimer = setInterval(() => {
        if (this.stopCount > 1) {
          this.stopCount -= 1;
        } else {
          this.startCountTimer && clearInterval(this.startCountTimer);
          this.stopCount = 20;
          this.leave();
        }
      }, 1000);
    },
    async join() {
      this.trtcState = "join";
    },
    taggleShowText() {
      console.log("taggleShowText");
      if (this.showRobot && !this.showRobotVideo) {
        return;
      }
      this.showText = !this.showText;
    },
  },
};
</script>

<style lang="less" scoped>
.voice-bg {
  width: 100%;
  height: 100%;
}
.mobile-voice-bg {
  width: 100%;
  height: 100%;
  border-radius: 6px;
  background: linear-gradient(
      125deg,
      rgba(255, 239, 250, 0.8) 21.83%,
      #def5ff 79.71%
    ),
    #fff;
  .voice-center {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    height: calc(100% - 220px);
    &.noShowRobot {
      margin-top: 50px;
      justify-content: center;
    }
  }
  .voice-avatar-robot {
    overflow: hidden;
    margin: auto;
    width: 26vh;
    height: 26vh;
    border-radius: 100%;
    background: #fff -46.362px -13.82px / 126.716% 234.165% no-repeat;
    border: 7.5px #fff solid;
    img {
      width: 100%;
      height: auto;
    }
    .loader {
      position: relative;
      cursor: not-allowed;
      position: absolute;
      width: 26vh;
      height: 26vh;
      left: auto;
      top: auto;
      scale: 1;
      transform: translate(0);
      display: -webkit-box;
      display: -ms-flexbox;
      display: flex;
      -webkit-box-align: center;
      -ms-flex-align: center;
      align-items: center;
      -webkit-box-pack: center;
      -ms-flex-pack: center;
      justify-content: center;
    }
    /deep/ .external-shadow {
      width: 26vh;
      height: 26vh;
    }
    /deep/ .central {
      width: 26vh;
      height: 26vh;
    }
    .remote-video {
      width: 100%;
    }
    .remote-video.yoyo {
      /deep/ video {
        width: 150% !important;
        background-color: #ffffff !important;
        margin-left: -25%;
        margin-top: -58%;
      }
    }
    .remote-video.lke2 {
      /deep/ video {
        width: 110% !important;
        background-color: #ffffff !important;
        margin-left: -5%;
        margin-top: -25%;
      }
    }
    .remote-video.lke1 {
      /deep/ video {
        width: 135% !important;
        background-color: #ffffff !important;
        margin-left: -18%;
        margin-top: -40%;
      }
    }
    .remote-video.zhiming {
      /deep/ video {
        width: 120% !important;
        background-color: #ffffff !important;
        margin-left: -10%;
        margin-top: -5%;
      }
    }

    &.with-txt {
      width: 20vh;
      height: 20vh;
      left: calc(50% - 80px);
    }
  }
  .displayText {
    width: 100%;
  }
  .transcriptionText {
    width: 100%;
    background: #fff;
  }
  .voice-info-cont {
    max-width: 80%;
    max-height: 30vh;
    overflow-x: hidden;
    overflow-y: scroll;
    margin-left: 10%;
    margin-bottom: 36px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
    flex-shrink: 0;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(
      to bottom,
      transparent 0%,
      black 15%,
      black 100%
    );
    mask-image: linear-gradient(
      to bottom,
      transparent 0%,
      black 15%,
      black 100%
    );

    &::-webkit-scrollbar {
      width: 0;
      height: 0;
      display: none;
    }

    &.robot-txt {
      height: 32%;
    }
    scrollbar-width: none;
    -ms-overflow-style: none;

    .user-question {
      color: var(--color-text-caption);
      font-family: var(--font-family-normal);
      font-size: 16px;
      font-style: normal;
      font-weight: 400;
      line-height: 24px;
      /* 150% */
    }

    .user-answer {
      color: var(--text---color-text-primary, rgba(0, 1, 11, 0.93));
      font-family: var(--font-family-normal);
      font-size: 16px;
      font-style: normal;
      font-weight: 400;
      line-height: 24px;
      /* 150% */
    }
  }
  .voice-avatar-cont {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 16px;
  }
  .voice-avatar {
    width: 64px;
    height: 64px;
    aspect-ratio: 1 / 1;
    border-radius: 6.4px;
    border: var(--border-thickness) solid var(--color-divider-normal);
    position: absolute;
    bottom: calc(50% - 32px);
    text-align: center;
    left: calc(50% - 32px);
    overflow: hidden;
    img {
      width: 100%;
      height: 100%;
    }
  }

  .voice-icon {
    color: var(--text---c-color-text-primary, rgba(0, 1, 12, 0.93));
    font-family: "PingFang SC";
    font-size: 16px;
    font-style: normal;
    font-weight: 500;
    line-height: 24px;
    /* 140% */

    position: absolute;
    bottom: calc(50% - 68px);
    text-align: center;
    width: 100%;
    text-align: center;
  }

  .voice-op-cont {
    bottom: 8%;
    position: absolute;
    width: 100%;
  }
  .voice-loading-cont {
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    gap: 8px;
    margin: auto;
    margin-bottom: 36px;
    text-align: center;
    width: fit-content;
    &.icon-pointer {
      cursor: pointer;
    }
  }

  .voice-loader-txt {
    color: var(--color-text-caption);

    /* subtitle/--subtitle-regular */
    font-family: var(--font-family-normal);
    font-size: 14px;
    font-style: normal;
    font-weight: 400;
    line-height: 24px;
    /* 150% */
  }

  .voice-btn-cont {
    display: flex;
    width: 100%;
    text-align: center;
    width: 80%;
    padding-left: 10%;
    padding-right: 10%;
    justify-content: space-between;
  }

  .voice-btn-mic {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    width: 80px;
    cursor: pointer;

    .mic-ico {
      background: var(--color-gray-0);
    }
  }

  .handup-btn-mic {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    width: 80px;
    cursor: pointer;

    .mic-ico {
      background: var(--color-error-normal);

      .mic-icon {
        transform: rotate(135deg);
        color: white;
      }
    }
  }

  .script-btn-mic {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    width: 80px;
    cursor: pointer;

    .mic-ico {
      background: var(--color-gray-0);
    }
  }

  .mic-ico {
    display: flex;
    padding: 17px;
    justify-content: center;
    align-items: center;
    gap: 8.5px;
    display: flex;
    padding: 17px;
    justify-content: center;
    align-items: center;
    gap: 8.5px;
    border-radius: 100%;
    background: var(--color-gray-0);

    .mic-icon {
      width: 34px;
      height: 34px;
    }
  }

  .info {
    position: absolute;
    bottom: 1%;
    text-align: center;
    width: 100%;

    color: var(--color-text-caption);

    /* subtitle/--subtitle-regular */
    font-family: var(--font-family-normal);
    font-size: 12px;
    font-style: normal;
    font-weight: 400;
    line-height: 24px;
    /* 150% */
  }

  // background: linear-gradient(125deg, color(display-p3 1 0.9381 0.9783 / 0.80) 21.83%, color(display-p3 0.8893 0.9594 1) 79.71%), color(display-p3 1 1 1);manage-voice-bg
  .voice-loading {
    display: flex;
  }

  .load {
    width: 2px;
    height: 33px;
    background-color: black;
    animation: 1s move6 infinite;
    border-radius: 5px;
    margin: 0.1em;
  }

  .load:nth-child(1) {
    animation-delay: 0.2s;
  }

  .load:nth-child(2) {
    animation-delay: 0.4s;
  }

  .load:nth-child(3) {
    animation-delay: 0.6s;
  }

  .loader-voice {
    display: flex;
    flex-direction: row;
    transform: rotate(180deg);
    justify-content: right;
    border-radius: 10px;
    transition: 0.4s ease-in-out;
  }
}
.manage-side-wrap {
  .manage-voice-bg {
    width: 100%;
    height: calc(100% + 64px);
    border-radius: 6px;
    background: linear-gradient(
        125deg,
        rgba(255, 239, 250, 0.8) 21.83%,
        #def5ff 79.71%
      ),
      #fff;
    margin-top: -64px;
    padding-top: 64px;
    .voice-center {
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      height: calc(100% - 320px);
      &.noShowRobot {
        justify-content: center;
      }
    }
    .voice-avatar-robot {
      overflow: hidden;
      margin: auto;
      width: 26vh;
      height: 26vh;
      border-radius: 100%;
      background: #fff -46.362px -13.82px / 126.716% 234.165% no-repeat;
      border: 7.5px #fff solid;
      img {
        width: 100%;
        height: auto;
      }
      .loader {
        position: relative;
        cursor: not-allowed;
        position: absolute;
        width: 26vh;
        height: 26vh;
        left: auto;
        top: auto;
        scale: 1;
        transform: translate(0);
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;
        -webkit-box-align: center;
        -ms-flex-align: center;
        align-items: center;
        -webkit-box-pack: center;
        -ms-flex-pack: center;
        justify-content: center;
      }
      /deep/ .external-shadow {
        width: 26vh;
        height: 26vh;
      }
      /deep/ .central {
        width: 26vh;
        height: 26vh;
      }
      .remote-video {
        width: 100%;
      }
      .remote-video.yoyo {
        /deep/ video {
          width: 150% !important;
          background-color: #ffffff !important;
          margin-left: -25%;
          margin-top: -58%;
        }
      }
      .remote-video.lke2 {
        /deep/ video {
          width: 110% !important;
          background-color: #ffffff !important;
          margin-left: -5%;
          margin-top: -25%;
        }
      }
      .remote-video.lke1 {
        /deep/ video {
          width: 135% !important;
          background-color: #ffffff !important;
          margin-left: -18%;
          margin-top: -40%;
        }
      }
      .remote-video.zhiming {
        /deep/ video {
          width: 120% !important;
          background-color: #ffffff !important;
          margin-left: -10%;
          margin-top: -5%;
        }
      }

      &.with-txt {
        width: 20vh;
        height: 20vh;
        left: calc(50% - 80px);
      }
    }
    .displayText {
      width: 100%;
    }
    .transcriptionText {
      width: 100%;
      background: #fff;
    }
    .voice-info-cont {
      max-width: 80%;
      max-height: 30vh;
      overflow-x: hidden;
      overflow-y: scroll;
      margin-left: 10%;
      margin-bottom: 36px;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 16px;
      flex-shrink: 0;
      scrollbar-width: none;
      -webkit-mask-image: linear-gradient(
        to bottom,
        transparent 0%,
        black 15%,
        black 100%
      );
      mask-image: linear-gradient(
        to bottom,
        transparent 0%,
        black 15%,
        black 100%
      );

      &::-webkit-scrollbar {
        width: 0;
        height: 0;
        display: none;
      }

      &.robot-txt {
        bottom: 35%;
        height: 30%;
      }
      scrollbar-width: none;
      -ms-overflow-style: none;

      .user-question {
        color: var(--color-text-caption);
        font-family: var(--font-family-normal);
        font-size: 16px;
        font-style: normal;
        font-weight: 400;
        line-height: 24px;
        /* 150% */
      }

      .user-answer {
        color: var(--text---color-text-primary, rgba(0, 1, 11, 0.93));
        font-family: var(--font-family-normal);
        font-size: 16px;
        font-style: normal;
        font-weight: 400;
        line-height: 24px;
        /* 150% */
      }
    }

    .voice-avatar {
      width: 120px;
      height: 120px;
      aspect-ratio: 1 / 1;
      border-radius: 12px;
      border: var(--border-thickness) solid var(--color-divider-normal);
      margin: auto;
      overflow: hidden;
      img {
        width: 100%;
        height: 100%;
      }
    }

    .voice-icon {
      color: var(--color-text-primary);
      font-family: var(--font-family-normal);
      font-size: 20px;
      font-style: normal;
      font-weight: 600;
      line-height: 28px;
      width: 100%;
      text-align: center;
      margin-top: 24px;
    }
    .voice-op-cont {
      bottom: 8%;
      position: absolute;
      width: 100%;
    }
    .voice-loading-cont {
      display: flex;
      -webkit-box-orient: vertical;
      -webkit-box-direction: normal;
      -ms-flex-direction: column;
      flex-direction: column;
      -webkit-box-align: center;
      -ms-flex-align: center;
      align-items: center;
      gap: 8px;
      margin: auto;
      margin-bottom: 36px;
      text-align: center;
      width: fit-content;
      &.icon-pointer {
        cursor: pointer;
      }
    }

    .voice-loader-txt {
      color: var(--color-text-caption);

      /* subtitle/--subtitle-regular */
      font-family: var(--font-family-normal);
      font-size: 14px;
      font-style: normal;
      font-weight: 400;
      line-height: 24px;
      /* 150% */
    }

    .voice-btn-cont {
      display: flex;
      -webkit-box-align: center;
      -ms-flex-align: center;
      align-items: center;
      gap: 100px;
      -webkit-box-pack: justify;
      -ms-flex-pack: justify;
      justify-content: space-between;
      -ms-flex-item-align: stretch;
      align-self: stretch;
      text-align: center;
      width: fit-content;
      margin: auto;
    }

    .voice-btn-mic {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 12px;
      width: 80px;
      cursor: pointer;

      .mic-ico {
        background: var(--color-gray-0);
      }
    }

    .handup-btn-mic {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 12px;
      width: 80px;
      cursor: pointer;

      .mic-ico {
        background: var(--color-error-normal);

        .mic-icon {
          transform: rotate(135deg);
          color: white;
        }
      }
    }

    .script-btn-mic {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 12px;
      width: 80px;
      cursor: pointer;

      .mic-ico {
        background: var(--color-gray-0);
      }
    }

    .mic-ico {
      display: flex;
      padding: 17px;
      justify-content: center;
      align-items: center;
      gap: 8.5px;
      display: flex;
      padding: 17px;
      justify-content: center;
      align-items: center;
      gap: 8.5px;
      border-radius: 100%;
      background: var(--color-gray-0);

      .mic-icon {
        width: 34px;
        height: 34px;
      }
    }

    .mic-txt {
      color: var(--color-text-secondary);

      /* subtitle/--subtitle-regular */
      font-family: var(--font-family-normal);
      font-size: 14px;
      font-style: normal;
      font-weight: 400;
      line-height: 24px;
      /* 150% */
    }

    .info {
      position: absolute;
      bottom: 1%;
      text-align: center;
      width: 100%;

      color: var(--color-text-caption);

      /* subtitle/--subtitle-regular */
      font-family: var(--font-family-normal);
      font-size: 12px;
      font-style: normal;
      font-weight: 400;
      line-height: 24px;
      /* 150% */
    }

    // background: linear-gradient(125deg, color(display-p3 1 0.9381 0.9783 / 0.80) 21.83%, color(display-p3 0.8893 0.9594 1) 79.71%), color(display-p3 1 1 1);manage-voice-bg
    .voice-loading {
      display: flex;
    }

    .load {
      width: 2px;
      height: 33px;
      background-color: black;
      animation: 1s move6 infinite;
      border-radius: 5px;
      margin: 0.1em;
    }

    .load:nth-child(1) {
      animation-delay: 0.2s;
    }

    .load:nth-child(2) {
      animation-delay: 0.4s;
    }

    .load:nth-child(3) {
      animation-delay: 0.6s;
    }

    .loader-voice {
      display: flex;
      flex-direction: row;
      transform: rotate(180deg);
      justify-content: right;
      border-radius: 10px;
      transition: 0.4s ease-in-out;
    }
  }
  @media (max-height: 600px) {
    .voice-avatar-robot {
      display: none !important;
    }
  }
  @media (max-height: 400px) {
    .voice-center {
      display: none !important;
    }
  }
}
.client-side-wrap {
  .manage-voice-bg {
    width: 100%;
    height: calc(100% + 64px);
    border-radius: 6px;
    background: linear-gradient(
        125deg,
        rgba(255, 239, 250, 0.8) 21.83%,
        #def5ff 79.71%
      ),
      #fff;
    margin-top: -64px;
    padding-top: 64px;
    .voice-center {
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      height: calc(100% - 220px);
      &.noShowRobot {
        justify-content: center;
      }
    }
    .voice-avatar-robot {
      overflow: hidden;
      margin: auto;
      width: 26vh;
      height: 26vh;
      border-radius: 100%;
      background: #fff -46.362px -13.82px / 126.716% 234.165% no-repeat;
      border: 7.5px #fff solid;
      img {
        width: 100%;
        height: auto;
      }
      .loader {
        position: relative;
        cursor: not-allowed;
        position: absolute;
        width: 26vh;
        height: 26vh;
        left: auto;
        top: auto;
        scale: 1;
        transform: translate(0);
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;
        -webkit-box-align: center;
        -ms-flex-align: center;
        align-items: center;
        -webkit-box-pack: center;
        -ms-flex-pack: center;
        justify-content: center;
      }
      /deep/ .external-shadow {
        width: 26vh;
        height: 26vh;
      }
      /deep/ .central {
        width: 26vh;
        height: 26vh;
      }
      .remote-video {
        width: 100%;
      }
      .remote-video.yoyo {
        /deep/ video {
          width: 150% !important;
          background-color: #ffffff !important;
          margin-left: -25%;
          margin-top: -58%;
        }
      }
      .remote-video.lke2 {
        /deep/ video {
          width: 110% !important;
          background-color: #ffffff !important;
          margin-left: -5%;
          margin-top: -25%;
        }
      }
      .remote-video.lke1 {
        /deep/ video {
          width: 135% !important;
          background-color: #ffffff !important;
          margin-left: -18%;
          margin-top: -40%;
        }
      }

      .remote-video.zhiming {
        /deep/ video {
          width: 120% !important;
          background-color: #ffffff !important;
          margin-left: -10%;
          margin-top: -5%;
        }
      }

      &.with-txt {
        width: 20vh;
        height: 20vh;
        left: calc(50% - 80px);
      }
    }
    .displayText {
      width: 100%;
    }
    .transcriptionText {
      width: 100%;
      background: #fff;
    }
    .voice-info-cont {
      max-width: 80%;
      max-height: 30vh;
      overflow-x: hidden;
      overflow-y: scroll;
      margin-left: 10%;
      margin-bottom: 36px;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 16px;
      flex-shrink: 0;
      scrollbar-width: none;
      -webkit-mask-image: linear-gradient(
        to bottom,
        transparent 0%,
        black 15%,
        black 100%
      );
      mask-image: linear-gradient(
        to bottom,
        transparent 0%,
        black 15%,
        black 100%
      );

      &::-webkit-scrollbar {
        width: 0;
        height: 0;
        display: none;
      }

      &.robot-txt {
        bottom: 35%;
        height: 30%;
      }
      scrollbar-width: none;
      -ms-overflow-style: none;

      .user-question {
        color: var(--color-text-caption);
        font-family: var(--font-family-normal);
        font-size: 16px;
        font-style: normal;
        font-weight: 400;
        line-height: 24px;
        /* 150% */
      }

      .user-answer {
        color: var(--text---color-text-primary, rgba(0, 1, 11, 0.93));
        font-family: var(--font-family-normal);
        font-size: 16px;
        font-style: normal;
        font-weight: 400;
        line-height: 24px;
        /* 150% */
      }
    }

    .voice-avatar {
      width: 120px;
      height: 120px;
      aspect-ratio: 1 / 1;
      border-radius: 12px;
      border: var(--border-thickness) solid var(--color-divider-normal);
      margin: auto;
      overflow: hidden;
      img {
        width: 100%;
        height: 100%;
      }
    }

    .voice-icon {
      color: var(--color-text-primary);
      font-family: var(--font-family-normal);
      font-size: 20px;
      font-style: normal;
      font-weight: 600;
      line-height: 28px;
      width: 100%;
      text-align: center;
      margin-top: 24px;
    }
    .voice-op-cont {
      bottom: 8%;
      position: absolute;
      width: 100%;
    }
    .voice-loading-cont {
      display: flex;
      -webkit-box-orient: vertical;
      -webkit-box-direction: normal;
      -ms-flex-direction: column;
      flex-direction: column;
      -webkit-box-align: center;
      -ms-flex-align: center;
      align-items: center;
      gap: 8px;
      margin: auto;
      margin-bottom: 36px;
      text-align: center;
      width: fit-content;
      &.icon-pointer {
        cursor: pointer;
      }
    }

    .voice-loader-txt {
      color: var(--color-text-caption);

      /* subtitle/--subtitle-regular */
      font-family: var(--font-family-normal);
      font-size: 14px;
      font-style: normal;
      font-weight: 400;
      line-height: 24px;
      /* 150% */
    }

    .voice-btn-cont {
      display: flex;
      -webkit-box-align: center;
      -ms-flex-align: center;
      align-items: center;
      gap: 100px;
      -webkit-box-pack: justify;
      -ms-flex-pack: justify;
      justify-content: space-between;
      -ms-flex-item-align: stretch;
      align-self: stretch;
      text-align: center;
      width: fit-content;
      margin: auto;
    }

    .voice-btn-mic {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 12px;
      width: 80px;
      cursor: pointer;

      .mic-ico {
        background: var(--color-gray-0);
      }
    }

    .handup-btn-mic {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 12px;
      width: 80px;
      cursor: pointer;

      .mic-ico {
        background: var(--color-error-normal);

        .mic-icon {
          transform: rotate(135deg);
          color: white;
        }
      }
    }

    .script-btn-mic {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 12px;
      width: 80px;
      cursor: pointer;

      .mic-ico {
        background: var(--color-gray-0);
      }
    }

    .mic-ico {
      display: flex;
      padding: 17px;
      justify-content: center;
      align-items: center;
      gap: 8.5px;
      display: flex;
      padding: 17px;
      justify-content: center;
      align-items: center;
      gap: 8.5px;
      border-radius: 100%;
      background: var(--color-gray-0);

      .mic-icon {
        width: 34px;
        height: 34px;
      }
    }

    .mic-txt {
      color: var(--color-text-secondary);

      /* subtitle/--subtitle-regular */
      font-family: var(--font-family-normal);
      font-size: 14px;
      font-style: normal;
      font-weight: 400;
      line-height: 24px;
      /* 150% */
    }

    .info {
      position: absolute;
      bottom: 1%;
      text-align: center;
      width: 100%;

      color: var(--color-text-caption);

      /* subtitle/--subtitle-regular */
      font-family: var(--font-family-normal);
      font-size: 12px;
      font-style: normal;
      font-weight: 400;
      line-height: 24px;
      /* 150% */
    }

    // background: linear-gradient(125deg, color(display-p3 1 0.9381 0.9783 / 0.80) 21.83%, color(display-p3 0.8893 0.9594 1) 79.71%), color(display-p3 1 1 1);manage-voice-bg
    .voice-loading {
      display: flex;
    }

    .load {
      width: 2px;
      height: 33px;
      background-color: black;
      animation: 1s move6 infinite;
      border-radius: 5px;
      margin: 0.1em;
    }

    .load:nth-child(1) {
      animation-delay: 0.2s;
    }

    .load:nth-child(2) {
      animation-delay: 0.4s;
    }

    .load:nth-child(3) {
      animation-delay: 0.6s;
    }

    .loader-voice {
      display: flex;
      flex-direction: row;
      transform: rotate(180deg);
      justify-content: right;
      border-radius: 10px;
      transition: 0.4s ease-in-out;
    }
  }
  @media (max-height: 600px) {
    .voice-avatar-robot {
      display: none !important;
    }
  }
  @media (max-height: 400px) {
    .voice-center {
      display: none !important;
    }
  }
}
.typing-indicator {
  width: 60px;
  height: 30px;
  position: relative;
  z-index: 4;
}

.typing-circle {
  width: 8px;
  height: 8px;
  position: absolute;
  border-radius: 50%;
  background-color: #000;
  left: 15%;
  &.circle-animation {
    transform-origin: 50%;
    animation: typing-circle7124 0.5s alternate infinite ease;
  }
}

@keyframes typing-circle7124 {
  0% {
    top: 20px;
    height: 5px;
    border-radius: 50px 50px 25px 25px;
    transform: scaleX(1.7);
  }

  40% {
    height: 8px;
    border-radius: 50%;
    transform: scaleX(1);
  }

  100% {
    top: 0%;
  }
}

.typing-circle:nth-child(2) {
  left: 45%;
  animation-delay: 0.2s;
}

.typing-circle:nth-child(3) {
  left: auto;
  right: 15%;
  animation-delay: 0.3s;
}

@keyframes move6 {
  0% {
    height: 0.2em;
  }

  25% {
    height: 0.7em;
  }

  50% {
    height: 1.5em;
  }

  100% {
    height: 0.2em;
  }
}
</style>